// server/security-helpers.js
/**
 * Security Helpers for WebSocket Server
 * Handles segmentation, pattern matching, and access logging
 */
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

// Configuration
const LOG_DIR = process.env.LOG_DIR || path.join(__dirname, 'logs');
const ACCESS_LOG = path.join(LOG_DIR, 'access_log.txt');

// Segmentation configuration
const TOTAL_RECORDS = 3550; // Total number of records in ds_customers table
const NUM_SEGMENTS = 12;    // Number of segments to divide the year into
const SEGMENT_SIZE = Math.ceil(TOTAL_RECORDS / NUM_SEGMENTS); // ~296 records per segment

/**
 * Logging helper
 */
function log(label, data = null) {
  const timestamp = new Date().toISOString();
  console.log(`[${timestamp}] [SECURITY] ${label}`);
  if (data) {
    console.log(JSON.stringify(data, null, 2));
  }
}

/**
 * Ensures log directory exists
 */
function ensureLogDir() {
  if (!fs.existsSync(LOG_DIR)) {
    fs.mkdirSync(LOG_DIR, { recursive: true });
    log(`Created log directory: ${LOG_DIR}`);
  }
}

/**
 * Log access to a file
 */
function logAccess(ip, email, recordCount) {
  ensureLogDir();
  
  const now = new Date();
  const logEntry = `${ip} ${now.toISOString()} ${recordCount}\n`;
  
  // Create a unique log file for each subscriber
  const md5Hash = crypto.createHash('md5').update(email || 'unknown').digest('hex');
  const epoch = Math.floor(Date.now() / 1000);
  const logFile = path.join(LOG_DIR, `tempfile_${md5Hash}_${epoch}.file`);
  
  // Append to global access log
  fs.appendFileSync(ACCESS_LOG, logEntry, { encoding: 'utf8' });
  
  // Create or append to user-specific log
  fs.appendFileSync(logFile, logEntry, { encoding: 'utf8' });
  
  log(`Logged access for ${email || 'unknown'}: ${recordCount} records from ${ip}`);
  return logFile;
}

/**
 * Calculate current segment based on time of year
 */
function getCurrentSegment() {
  const now = new Date();
  const month = now.getMonth(); // 0-11
  
  // Map month to segment (12 segments per year)
  return Math.floor((month / 12) * NUM_SEGMENTS);
}

/**
 * Get ID range for current segment
 */
function getSegmentIdRange() {
  const segment = getCurrentSegment();
  const startId = (segment * SEGMENT_SIZE) + 1;
  const endId = Math.min(startId + SEGMENT_SIZE - 1, TOTAL_RECORDS);
  
  return { startId, endId, segment };
}

/**
 * Check if function is using our frontend pattern
 */
function matchesFrontendPattern(functionId, functionBody) {
  // Check if function ID follows expected pattern from our loader
  const validIdPattern = /^_var_www_[\w\/]+_src_(components|pages|utils)_[\w\/]+_js_block_\d+$/;
  if (!validIdPattern.test(functionId)) {
    return false;
  }
  
  // If accessing ds_customers table, ensure it uses our segment range logic
  if (functionBody.includes('ds_customers') || 
      functionBody.includes('mysql2/promise')) {
    
    // Should create/update a file for tracking
    const hasFileOps = functionBody.includes('fs.writeFile') || 
                       functionBody.includes('fs.promises.writeFile') ||
                       functionBody.includes('writeSubscriptionFile');
    
    if (!hasFileOps) {
      log(`Function accessing ds_customers doesn't include file operations`);
      return false;
    }
    
    // Function should filter records by date
    const hasDateFiltering = functionBody.includes('thirtyDaysAgo') &&
                             functionBody.includes('filter');
    
    if (!hasDateFiltering) {
      log(`Function accessing ds_customers doesn't include date filtering`);
      return false;
    }
  }
  
  return true;
}

/**
 * Modify SQL queries to enforce segmentation
 */
function enforceSegmentation(code) {
  // Only modify if accessing ds_customers table
  if (!code.includes('ds_customers')) {
    return code;
  }
  
  // Get current segment range
  const { startId, endId, segment } = getSegmentIdRange();
  log(`Current segment: ${segment}, ID range: ${startId}-${endId}`);
  
  // Find SQL queries and add segment constraints
  let modifiedCode = code;
  
  // Match any SELECT statements on ds_customers
  const selectPattern = /SELECT\s+.*\s+FROM\s+(\w+\.)?ds_customers\s+/gi;
  
  // Add segment constraint to WHERE clauses
  modifiedCode = modifiedCode.replace(selectPattern, (match) => {
    // Add WHERE or AND for ID range
    if (match.toLowerCase().includes('where')) {
      return `${match}AND cID BETWEEN ${startId} AND ${endId} `;
    } else {
      return `${match}WHERE cID BETWEEN ${startId} AND ${endId} `;
    }
  });
  
  if (modifiedCode !== code) {
    log(`Modified query to enforce segment constraints (${startId}-${endId})`);
  }
  
  return modifiedCode;
}

module.exports = {
  log,
  logAccess,
  getCurrentSegment,
  getSegmentIdRange,
  matchesFrontendPattern,
  enforceSegmentation,
  ensureLogDir,
  TOTAL_RECORDS,
  NUM_SEGMENTS,
  SEGMENT_SIZE
};

